package org.andao.security.filter;

import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.andao.core.support.context.SpringContextHolder;
import org.andao.core.utils.ExDateUtils;
import org.andao.core.utils.ExStringUtils;
import org.andao.core.utils.HttpServletUtils;
import org.andao.core.utils.JsonUtils;
import org.andao.security.SpringSecurityHelper;
import org.andao.security.model.User;
import org.andao.security.verifyimage.CaptchaServiceSingleton;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.security.util.RedirectUtils;



/**
 * 用户登录扩展过滤器.
 * 用来处理登录过程中的事项，如验证码、载入用户安全会话等，主要是扩展spring security中不能满足的情况.<p>
 * 
 * @author Marco.hu(hzg139@163.com)
 */
public class ExAuthenticationProcessingFilter extends AuthenticationProcessingFilter{		
	
	public static final String SPRING_SECURITY_FORM_TAGETURL_KEY = "redirectURL";//需要跳转的URL
	public static final String SPRING_SECURITY_FORM_FAILUREURL_KEY = "failureURL";//验证失败返回的自定义URL
	public static final String SPRING_SECURITY_USERLOGINNUM = "loginNum";//用户登录次数
	  
	 private boolean useRelativeContext = false; 
	 	
	 @Override
	 protected void onPreAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException,	IOException {
		 String defaultTargetUrl = request.getParameter(SPRING_SECURITY_FORM_TAGETURL_KEY);//自定义默认跳转
		  if(ExStringUtils.isNotBlank(defaultTargetUrl)){
			  setDefaultTargetUrl(defaultTargetUrl);
		  }
		 		  
		  String authenticationFailureUrl = request.getParameter(SPRING_SECURITY_FORM_FAILUREURL_KEY);
		  if(ExStringUtils.isNotBlank(authenticationFailureUrl)){
			  setAuthenticationFailureUrl(authenticationFailureUrl);//自定义错误跳转url
		  }	
		super.onPreAuthentication(request, response);
	}

	 
	/*
	 * 登录成功后的处理扩展
	*/
	@Override
	protected void onSuccessfulAuthentication(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Authentication authentication) throws IOException {	
		modifyUserInfo(servletRequest);				
		//清除用户登录次数
		servletRequest.getSession(false).removeAttribute(SPRING_SECURITY_USERLOGINNUM);
		super.onSuccessfulAuthentication(servletRequest, servletResponse, authentication);
		
		if ("XMLHttpRequest".equals(servletRequest.getHeader("X-Requested-With"))){  //使用ajax方式请求                        
            if(logger.isDebugEnabled()) 
            	logger.debug("使用ajax登录...");
            HttpServletUtils.render(servletResponse, "application/json",
            		JsonUtils.mapToJson(Collections.singletonMap("statusCode", HttpServletResponse.SC_OK)));  
        }  
	}
	
	private void modifyUserInfo(HttpServletRequest servletRequest){
		try {		
			User user = SpringSecurityHelper.getCurrentUser();			
			user.setLoginIp(HttpServletUtils.getIpAddr(servletRequest));
			user.setLastLoginTime(new Date());
			logger.info("user:"+user+" logined at {"+ExDateUtils.getToday().getTime()+"}");	
		} catch (Exception e) {
			logger.error(e.fillInStackTrace());
		}
		
	}
	
	/*
	 * 登录失败后处理扩展
	 */
	@Override
	protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {		
		 super.onUnsuccessfulAuthentication(request, response, exception);		 
		 if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){  //by ajax
	            Map<String, Object> message = new HashMap<String, Object>();  	        
	            message.put("statusCode", HttpServletResponse.SC_UNAUTHORIZED);  
	            message.put("message", exception.getMessage());  
	            HttpServletUtils.render(response, "application/json",JsonUtils.mapToJson(message)); 
	        }  		
	}

	/*
	 * 登录前处理扩展，比如验证码处理等	
	 */
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {		
		//RequestContext ctx = new RequestContext(request);		
		ResourceBundleMessageSource msgSource = (ResourceBundleMessageSource)SpringContextHolder.getBean("messageSource");
		
		int loginNum = 1;
		HttpSession session = request.getSession(true);
		
		//用户尝试登录次数超过3次，则需要校验码
		if(null != session.getAttribute(SPRING_SECURITY_USERLOGINNUM)){
			loginNum = (Integer)session.getAttribute(SPRING_SECURITY_USERLOGINNUM)+1;
		}
	
		session.setAttribute(SPRING_SECURITY_USERLOGINNUM,loginNum );
		
		//处理验证码
		String checkcode = ExStringUtils.trimToEmpty(request.getParameter("j_checkcode"));
		if(loginNum>3 && 
				!isValidateCode(session,checkcode)){//如果验证码错误				
			throw new BadCredentialsException(msgSource.getMessage("CAPTCHA", null, request.getLocale()));
			
		}	
		return super.attemptAuthentication(request);
	}

	@Override
	protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
            throws IOException {
		if (!"XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){  //使用非ajax方式请求时
            RedirectUtils.sendRedirect(request, response, url, useRelativeContext);  
        }  
	}
	
	/*
	 * 校验验证码是否正确
	 */
	private boolean isValidateCode(HttpSession  session,String validateCode) {		
		return CaptchaServiceSingleton.getInstance().validateCaptchaResponse(validateCode.trim(), session);  		 
	}
	
	
	
}
